package com.disputemanager.info;

import java.io.File;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.apache.log4j.Logger;

import com.disputemanager.beans.AllDisputeCounts;
import com.disputemanager.beans.CaseHistoryBean;
import com.disputemanager.beans.CaseLogBean;
import com.disputemanager.beans.Dispute;
import com.disputemanager.config.Constants;
import com.disputemanager.db.DBHandler;
import com.google.gson.Gson;
import com.sun.jersey.core.header.ContentDisposition;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;

@Path("info")
public class InformationService {
	
	private final Logger LOGGER = Logger.getLogger(InformationService.class);
	
	/* service method to Login call.
	 * input : username & password
	 * output : success/failure - plain text */
	@POST
	@Path("login")
	@Produces(MediaType.TEXT_PLAIN)
	public String login(@FormParam("username") String username,
			@FormParam("password") String password){
		
		LOGGER.debug("SERVICE : LOGIN ["+ username +","+password+"]");
		
		DBHandler todb = new DBHandler();
		int merchantId = 0;
		try {
			if((merchantId = todb.login(username, password)) != 0)
				return String.valueOf(merchantId);
			
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving login information.", e);
		}
		
		return String.valueOf(merchantId);		
	}
	
	/* Service method to get the dispute counts for CB/RT cases group by the product code.
	 * 1 - Visa
	 * 2 - MC
	 * 3 - Discover
	 * 4 - Amex
	 * input : merchant id
	 * output : AllDisputeCounts bean as Json data */
	@POST
	@Path("getDisputeCounts")
	@Produces(MediaType.APPLICATION_JSON)
	public String getDisputeCounts(@FormParam("merchantId") String merchantId){
		
		LOGGER.debug("SERVICE : GET DISPUTE COUNTS ["+ merchantId +"]");
		
		AllDisputeCounts countOfDispute = new AllDisputeCounts();
		Map<String, Integer> cb = null;
		Map<String, Integer> rt = null;
		Gson gson = new Gson();
		String jsonData = null;
		
		DBHandler todb = new DBHandler();
		try {
			ResultSet result = todb.getDisputeCountsByProdCode(merchantId);
			if(result != null){
				cb = new HashMap<String, Integer>();
				rt = new HashMap<String, Integer>();
				while(result.next()){
					
					if(result.getString("disputeDesc").trim().equals(Constants.CB)){
						cb.put(Constants.prodCodes.get(result.getInt("prodCode")), result.getInt("CCount"));
					}else if(result.getString("disputeDesc").trim().equals(Constants.RT)){
						rt.put(Constants.prodCodes.get(result.getInt("prodCode")), result.getInt("CCount"));
					}
				}
				
				countOfDispute.setCb(cb);
				countOfDispute.setRt(rt);
			}
			
			jsonData = gson.toJson(countOfDispute);
			
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving dispute count by prod code information for merchants.", e);
		}
		
		return jsonData;
	}
	
	/* service method to get all the dispute details [at the time when you tap on a association] 
	 * input : merchant id, product code[1,2,3,4], dispute type[CB/RT]
	 * output : a list of dispute beans in form of Json data*/
	@POST
	@Path("getAllDisputes")
	@Produces(MediaType.APPLICATION_JSON)
	public String getAllDisputeDetails(@FormParam("merchantId") String merchantId,
			@FormParam("prodCode") String prodCode,
			@FormParam("disputeType") String disputeType){
		
		LOGGER.debug("SERVICE : GET ALL DISPUTES ["+ merchantId +","+ prodCode+","+disputeType+"]");
		
		List<Dispute> disputes = new ArrayList<Dispute>();
		Gson gson = new Gson();
		String jsonData = null;
		DBHandler toDb = new DBHandler();
		
		try {
			disputes = toDb.getAllDisputeDetails(merchantId, prodCode, disputeType);
			jsonData = gson.toJson(disputes);
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving dispute information.", e);
		}
		
		return jsonData;
	}

	/* service method to get all information about a single dispute
	 * input : dispute id
	 * output : a dispute bean in form of Json data */
	@POST
	@Path("getDispute")
	@Produces(MediaType.APPLICATION_JSON)
	public String getDisputeDetails(@FormParam("disputeId") String disputeId){
		
		LOGGER.debug("SERVICE : GET DISPUTE ["+ disputeId +"]");
		
		int disputeNo = Integer.parseInt(disputeId);
		Dispute disputeBean = null;
		Gson gson = new Gson();
		String jsonDisputeObj = null;
		DBHandler todb = new DBHandler();
		try {
			disputeBean = todb.getDisputeDetail(disputeNo);
			jsonDisputeObj = gson.toJson(disputeBean);
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving dispute information.", e);
		}
		
		return jsonDisputeObj;
	}
	
	/* Service method when you apply an action[Accept/Reject/Attach Note] to a dispute, 
	 * it will work as a method to change the status[W/C] of the corresponding dispute
	 * input : dispute id, action [Accept/ Reject/ Attach Note]
	 * output : success/failure as plain text */
	@POST
	@Path("changeDisputeStatus")// for accept, reject & attach note
	@Produces(MediaType.TEXT_PLAIN)
	public String changeDisputeStatus(@FormParam("disputeId") String disputeId,
			@FormParam("merchantId") String merchantId,
			@FormParam("action") String action){
		
		LOGGER.debug("SERVICE : CHANGE DISPUTE STATUS ["+ disputeId +","+ merchantId+","+action+"]");
		
		DBHandler todb = new DBHandler();
		if(todb.changeDisputeStatus(disputeId, merchantId, action))
			return Constants.ReturnStatusSuccess;
		
		return Constants.ReturnStatusFailure;
	}
	
	/* Service method to get all the information what happend to the case
	 * input : dispute id
	 * output : a list of case log bean in form of Json data */
	@POST
	@Path("getCaseLog")
	@Produces(MediaType.APPLICATION_JSON)
	public String getCaseLog(@FormParam("disputeId") String disputeId){
		
		LOGGER.debug("SERVICE : GET CASE LOG ["+ disputeId +"]");
		
		int disputeNo = Integer.parseInt(disputeId);
		List<CaseLogBean> beans = new ArrayList<CaseLogBean>();
		Gson gson = new Gson();
		String jsonData = null;
		DBHandler todb = new DBHandler();
		
		try {
			beans = todb.getCaseLog(disputeNo);
			jsonData = gson.toJson(beans);
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving dispute case log information.", e);
		}
		
		return jsonData;
	}
	
	/* Service method to get information what document added to the case [case history]
	 * input : dispute id
	 * output : a list of case history bean in form of Json data  */
	@POST
	@Path("getCaseHistory")
	@Produces(MediaType.APPLICATION_JSON)
	public String getCaseHistory(@FormParam("disputeId") String disputeId){
		
		LOGGER.debug("SERVICE : GET CASE HISTORY ["+ disputeId +"]");
		
		int disputeNo = Integer.parseInt(disputeId);
		List<CaseHistoryBean> beans = new ArrayList<CaseHistoryBean>();
		Gson gson = new Gson();
		String jsonData = null;
		DBHandler todb = new DBHandler();
		
		try {
			beans = todb.getCaseHistory(disputeNo);
			jsonData = gson.toJson(beans);
		} catch (ClassNotFoundException | SQLException e) {
			LOGGER.error("Error retrieving dispute case log information.", e);
		}
		
		return jsonData;
	}
	
	/* Service method to upload a document
	 * output : success/ failure a plain text */
	@POST
	@Path("uploadDocument")
	@Consumes(MediaType.MULTIPART_FORM_DATA)
	@Produces(MediaType.TEXT_PLAIN)
	public String uploadDocument(FormDataMultiPart form){
		
		LOGGER.debug("SERVICE : UPLOAD DOCUMENT ["+ form +"]");
		
		String status = Constants.ReturnStatusFailure;
		
		FormDataBodyPart filePart = form.getField("file");
		ContentDisposition fileContent = filePart.getContentDisposition();
		InputStream fileInput = filePart.getValueAs(InputStream.class);
		String fileName = fileContent.getFileName();
		if(fileName == null)
			fileName = "MSUP"+System.currentTimeMillis()+".jpg";
		String disputeId = form.getField("disputeId").getEntityAs(String.class);
		String merchantId = form.getField("merchantId").getEntityAs(String.class);
		
		String uploadFileLoc = Constants.DocumentRepository + File.separator + disputeId+"."+fileName;
		
		DBHandler todb = new DBHandler();
		boolean success = todb.doDocumentUpload(disputeId,merchantId, fileInput, uploadFileLoc);
		
		if(success)
			status = Constants.ReturnStatusSuccess;
		
		return status;
	}
	
	/* Service method to download a document
	 * output : either the file you want to download / file not found error */
	@GET
	@Path("download")
	public Response downloadDocument(@QueryParam("fileName") String filename){
		
		LOGGER.debug("SERVICE : GET DOWNLOAD DOCUMENT ["+ filename +"]");
		
		File file =  new File(Constants.DocumentRepository+File.separator+ filename);
		ResponseBuilder rb = null;
		if(file.exists()){
			rb = Response.ok((Object) file);
			rb.header("Content-Disposition", "attachment; filename="+filename);
		}else{
			rb=Response.status(404).entity("File not found !").type(MediaType.TEXT_PLAIN);
		}
		
		return rb.build();
	}
	
	/* Service method to attach a note to a particular dispute
	 * input : dispute id, note
	 * output : success / failure as plain text */
	@POST
	@Path("attachNote")
	@Produces(MediaType.TEXT_PLAIN)
	public String attachNote(@FormParam("disputeId") String disputeId,
			@FormParam("merchantId") String merchantId,
			@FormParam("note") String note){
		
		LOGGER.debug("SERVICE : ATTACH NOTE ["+ disputeId +","+note+"]");
		
		DBHandler todb = new DBHandler();
		if(todb.attachNote(disputeId,merchantId, note))
			return Constants.ReturnStatusSuccess;
		
		return Constants.ReturnStatusFailure;
	}

}
